package com.google.gwt.gwtpages.client.message;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.gwtpages.client.GWTPagesSettings;
import com.google.gwt.gwtpages.client.event.MessageChangeEvent;
import com.google.gwt.gwtpages.client.event.MessageChangeEvent.MessageChangeHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.inject.Inject;

/**
 * Default drop-in component used to display GWT Page messages. These messages
 * can be applied using the {@link Messages} class. Messages will automatically
 * be applied to this component as it receives {@link MessageChangeEvent}
 * events.
 * 
 * The DOM structure of the rendered output is: <div> <div class=
 * "messages {messages-success|messages-info|messages-warn|messages-error|messages-fatal}"
 * > <div class=
 * "message {message-success|message-info|message-warn|message-error|message-fatal}"
 * >message text</div> </div> </div>
 * 
 * @author Joe Hudson
 */
public class MessagePanel extends Composite implements MessageChangeHandler {

	private SimplePanel outerContainer;
	private FlowPanel messagesContainer;
	private boolean eventHandlerAttached = false;
	private GWTPagesSettings settings = null;

	public MessagePanel() {
		this(null);
	}

	@Inject
	public MessagePanel(GWTPagesSettings settings) {
		outerContainer = new SimplePanel();
		initWidget(outerContainer);
		outerContainer.add(this.messagesContainer = new FlowPanel());
		reset(new ArrayList<GWTMessage>(0));
		this.settings = settings;
	}

	@Override
	protected void onLoad() {
		super.onLoad();
		if (!eventHandlerAttached) {
			HandlerManager eventBus = (null != settings)?settings.getEventBus():GWTPagesSettings.get().getEventBus();
			eventBus.addHandler(MessageChangeEvent.TYPE, this);
			eventHandlerAttached = true;
		}
			
	}

	private void reset(List<GWTMessage> messages) {
		messagesContainer.clear();
		if (messages.size() == 0)
			outerContainer.setVisible(false);
		else {
			messagesContainer.setStyleName(null);
			HashMap<Integer, Integer> messageLevels = new HashMap<Integer, Integer>();
			outerContainer.setVisible(true);
			for (GWTMessage message : messages) {
				messageLevels.put(message.getLevel(), message.getLevel());
				messagesContainer.add(new MessageEntry(message));
			}
			if (messageLevels.size() == 1) {
				int level = messageLevels.values().iterator().next();
				if (level == GWTMessage.LEVEL_SUCCESS)
					messagesContainer.setStyleName("messages success-messages");
				else if (level == GWTMessage.LEVEL_ERROR)
					messagesContainer.setStyleName("messages error-messages");
				else if (level == GWTMessage.LEVEL_WARN)
					messagesContainer.setStyleName("messages warn-messages");
				else if (level == GWTMessage.LEVEL_INFO)
					messagesContainer.setStyleName("messages info-messages");
				else
					messagesContainer.setStyleName("messages");
			}
			else {
				messagesContainer.setStyleName("messages");
			}
			messagesContainer.getElement().scrollIntoView();
		}
	}

	public void onMessagesChanged(List<GWTMessage> messages) {
		reset(messages);
	}

	public class MessageEntry extends SimplePanel implements ClickHandler {
		private Focusable component;

		public MessageEntry(GWTMessage message) {
			if (null != message.getComponent()) {
				Anchor anchor = new Anchor(message.getMessage());
				this.component = message.getComponent();
				anchor.addClickHandler(this);
				add(anchor);
			} else {
				add(new Label(message.getMessage()));
			}
			if (message.getLevel() == GWTMessage.LEVEL_FATAL) {
				addStyleName("message fatal-message");
			} else if (message.getLevel() == GWTMessage.LEVEL_ERROR) {
				addStyleName("message error-message");
			} else if (message.getLevel() == GWTMessage.LEVEL_WARN) {
				addStyleName("message warn-message");
			} else if (message.getLevel() == GWTMessage.LEVEL_INFO) {
				addStyleName("message info-message");
			} else if (message.getLevel() == GWTMessage.LEVEL_SUCCESS) {
				addStyleName("message success-message");
			} else {
				addStyleName("message");
			}
		}

		public void onClick(ClickEvent event) {
			component.setFocus(true);
		}
	}
}